package com.yangfan.screenshot.service;

import android.Manifest;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

import com.wink_172.library.AppManager;
import com.yangfan.screenshot.R;
import com.yangfan.screenshot.event.EventCancelGesture;
import com.yangfan.screenshot.message.LocalMessageManager;
import com.yangfan.screenshot.ui.FloatButtonWindow;
import com.yangfan.screenshot.ui.MediaProjectActivity;
import com.yangfan.screenshot.message.MessageWhatConstant;
import com.yangfan.screenshot.ScreenShotManager;
import com.yangfan.screenshot.log.LogUtil;
import com.yangfan.screenshot.utils.BitmapUtil;
import com.yangfan.screenshot.utils.DeviceUtils;
import com.yangfan.screenshot.utils.FileUtil;
import com.yangfan.screenshot.utils.PermissionUtil;
import com.yangfan.screenshot.utils.ScreenUtil;
import com.yangfan.screenshot.utils.StitchUtil;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.nio.ByteBuffer;
import java.util.ArrayList;

/**
 * @author : yangfan
 * @date : 2022/12/8-21:53
 * desc   : 截屏核心服务
 *
 */
public class ScreenShotService extends Service implements LocalMessageManager.HandleMsgListener {
    boolean shot_screen=false;
    private final String TAG = ScreenShotService.class.getSimpleName();

    private static final String NOTIFICATION_CHANNEL_ID = "LongShot";
    private static final String NOTIFICATION_CHANNEL_NAME = "长截图";
    private static final String CHANNEL_DESCRIPTION = "this is default channel!";
    private static final int NOTIFICATION_ID = 11423;

    /**
     * 录屏相关
     */
    private MediaProjection mediaProjection;
    private MediaProjectionManager mediaProjectionManager;
    private ImageReader imageReader;
    private VirtualDisplay mVirtualDisplay;

    private ScreenShotManager.ScreenShotStateCallback mScreenShotStateCallback;

    private int screenWidth = 0;
    private int screenHeight = 0;

    private Handler mHandler;

    /**
     * 保存一次长截图的图片，用于后面计算合成
     */
    private ArrayList<Bitmap> bitmapList = new ArrayList<>();

    /**
     * 需要截图
     */
    private boolean capture = false;

    /**
     * 申请截屏权限结果信息
     */
    private int mResultCode;
    private Intent mResultIntent;

    /**
     * 悬浮窗
     */
    private FloatButtonWindow mFloatButtonWindow;

    private Object mCloseLock = new Object();

    /**
     * 是否点击完成按钮
     */
    private boolean isClickCompleteButton = false;

    @Override
    public void onCreate() {
        super.onCreate();
        LogUtil.d(TAG,"FloatWindowService onCreate====");
        LocalMessageManager.getInstance().addListener(this);
        HandlerThread handlerThread = new HandlerThread("AppShot");
        handlerThread.start();
        mHandler = new Handler(handlerThread.getLooper());

        screenWidth = ScreenUtil.instance.getWidth();
        screenHeight = ScreenUtil.instance.getHeight();

        notification();
        initFloatWindow();

        EventBus.getDefault().register(this);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new ScreenShotServiceBinder();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (mResultIntent == null
                && intent != null) {
            mResultIntent = intent.getParcelableExtra("intent_data");
            mResultCode = intent.getIntExtra("intent_code", -1);
            Log.e(TAG, "onStartCommand: ====>>" );
            captureLongStart();
        }
        return super.onStartCommand(intent, flags, startId);
    }



    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MessageWhatConstant.MESSAGE_WHAT_CAPTURE:
                LogUtil.d(TAG,"capture =" + capture);
//                mFloatButtonWindow.hide();
                capture = true;

                break;
            default:
                break;
        }
    }

    public class ScreenShotServiceBinder extends Binder {
        public ScreenShotService getService(){
            return ScreenShotService.this;
        }
    }

    public void setScreenShotCallback(ScreenShotManager.ScreenShotStateCallback screenShotStateCallback) {
        this.mScreenShotStateCallback = screenShotStateCallback;
    }

    private void initFloatWindow() {
        Log.e(TAG, "initFloatWindow: ====>>"+(mFloatButtonWindow==null) );
        if (mFloatButtonWindow == null) {
            mFloatButtonWindow = new FloatButtonWindow(this, new FloatButtonWindow.BtnListener() {

                @Override
                public void onShotBtnClick() {
                    LogUtil.d(TAG,"onShotBtnClick..====");
                    captureShotStart();
                }

                @Override
                public void onLongBtnClick() {
                    LogUtil.d(TAG,"onLongBtnClick..====");
                    captureLongStart();
                }

                @Override
                public void onCancelClick() {
                    LogUtil.d(TAG,"onCancelClick..====");
                    captureStop();
                }

                @Override
                public void onCompleteClick() {
                    LogUtil.d(TAG,"onCompleteClick..====");
                    isClickCompleteButton = true;
                    LocalMessageManager.getInstance().sendEmptyMessage(MessageWhatConstant.MESSAGE_WHAT_CAPTURE);
                }

                @Override
                public void onCloseClick() {
                    LogUtil.d(TAG,"onCloseClick..");
                    captureStop();
                    mFloatButtonWindow.hide();
                    AppManager.Companion.getAppManager().finishAllActivity();


//                    Intent stopIntent =new Intent(x.app(), ScreenShotService.class);
//                    stopService(stopIntent);
//                    onDestroy();
//                    AppManager.Companion.getAppManager().AppExit(org.xutils.x.app());
                }
            });
        }
    }

    /**
     * 执行合并相关动作
     */
    private void doMerge() {
        Log.e(TAG, "doMerge: ====>>" );
        isClickCompleteButton = false;
        release();
        mFloatButtonWindow.show();
        LocalMessageManager.getInstance().removeMessages(MessageWhatConstant.MESSAGE_WHAT_DO_SCROLL_START);
        mergeBitmap();
    }

    /**
     * 短截图开始
     * 申请录屏权限都在这里
     */
    public void captureShotStart(){
        shot_screen=true;
        LogUtil.d(TAG,"captureShotStart===="+shot_screen);

        if (checkPermissions()) {
            if (getMediaProjection()) {
                LogUtil.d(TAG,"申请到录屏权限，执行截屏");
                // 申请权限成功后
                // 先隐藏悬浮按钮
                // 先直接隐藏--刺激onImageAvailable回调
                mFloatButtonWindow.hide();
                capture = true;

                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mFloatButtonWindow.show();//刺激onImageAvailable回调

                    }
                },2000L);
            } else {
//                mFloatButtonWindow.show();
            }
        } else {
//            mFloatButtonWindow.show();
        }
    }
    /**
     * 长截图开始
     * 申请录屏权限都在这里
     */
    public void captureLongStart(){
        isClickCompleteButton=false;
        LogUtil.d(TAG,"captureLongStart===="+isClickCompleteButton);
        // 先直接隐藏
        mFloatButtonWindow.hide();
//        isClickCompleteButton=false;
        if (checkPermissions()) {
            if (getMediaProjection()) {
                LogUtil.d(TAG,"申请到录屏权限，执行截屏，并滑动");
                // 申请权限成功后，开始执行滑动
                // 先隐藏悬浮按钮
//                shot_screen=false;
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        capture = true;
                        FloatButtonWindow.Companion.setCancelNumber(0);
                        LocalMessageManager.getInstance().sendEmptyMessage(MessageWhatConstant.MESSAGE_WHAT_DO_SCROLL_START);
                    }
                },500L);
            } else {
//                mFloatButtonWindow.show();
            }
        } else {
//            mFloatButtonWindow.show();
        }
    }

    /**
     * 停止截图，释放资源
     */
    private void captureStop() {
        LogUtil.d(TAG,"captureStop..");
        capture = false;
        mFloatButtonWindow.show();
        LocalMessageManager.getInstance().removeMessages(MessageWhatConstant.MESSAGE_WHAT_DO_SCROLL_START);
        recycleBitmap();
        release();
    }

    private boolean getMediaProjection() {
        LogUtil.d(TAG,"getMediaProjection..");
        if (setUpMediaProjection(mResultIntent, mResultCode)) {
            initImageReader();
            virtualDisplay();
            return true;
        }
        reset();
        return false;
    }

    private boolean setUpMediaProjection(Intent mResultIntent, int mResultCode) {
        LogUtil.d(TAG,"mResultIntent = " + mResultIntent + ";mResultCode = " + mResultCode);
        if (mResultIntent != null) {
            try {
                if (mediaProjectionManager == null) {
                    mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
                }
                mediaProjection = mediaProjectionManager != null ? mediaProjectionManager.getMediaProjection(mResultCode, mResultIntent) : null;
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
        return false;
    }

    private void reset() {
        LogUtil.d(TAG,"reset..");
        this.mHandler.post(new Runnable() {
            @Override
            public final void run() {
                Intent intent = new Intent(ScreenShotService.this, MediaProjectActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
            }
        });
    }

    /**
     * 检查权限
     * @return
     */
    private boolean checkPermissions() {
        LogUtil.d(TAG,"checkPermissions..");
        String permiss=Manifest.permission.WRITE_EXTERNAL_STORAGE;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            permiss=   Manifest.permission.READ_MEDIA_IMAGES;
        }
        if (!PermissionUtil.checkPermission(getApplicationContext(), new String[]{permiss})) {
            Toast.makeText(getApplicationContext(), "请打开存储权限", Toast.LENGTH_SHORT).show();
            return false;
        }

        if (!DeviceUtils.isBackgroundStartAllowed(this)) {
            Toast.makeText(getApplicationContext(), "需要开启后台弹出界面权限", Toast.LENGTH_SHORT).show();
            Settings.canDrawOverlays(this);
            return false;
        }


        if (!PermissionUtil.hasAccessibilityPermission(this)) {
            Toast.makeText(getApplicationContext(), "请打开无障碍权限", Toast.LENGTH_SHORT).show();
            return false;
        }

        return true;
    }


    private void initImageReader(){
        LogUtil.d(TAG,"initImageReader..imageReader ==== " + imageReader);
        if (imageReader == null) {
            imageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888,2);
//            String path = FileUtil.instance.getSavePath(ScreenShotService.this);
            imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
                @Override
                public void onImageAvailable(ImageReader imageReader) {
                    synchronized (mCloseLock) {
                        Image image = imageReader.acquireLatestImage();
                        if (capture) {
                            try {
                                if (image != null) {
                                    LogUtil.d(TAG,"准备截图 getFormat ===== " + image.getFormat()+"   shot_screen:"+shot_screen);
                                    int width = image.getWidth();
                                    int height = image.getHeight();
                                    Image.Plane[] planes = image.getPlanes();
                                    ByteBuffer buffer = planes[0].getBuffer();
                                    int pixelStride = planes[0].getPixelStride();
                                    int rowStride = planes[0].getRowStride();
                                    int rowPadding = rowStride - pixelStride * width;
                                    Bitmap createBitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
                                    createBitmap.copyPixelsFromBuffer(buffer);

//                                    Bitmap save = Bitmap.createBitmap(createBitmap,0,createBitmap.getHeight() - ScreenUtil.instance.getNavigationBarHeight(),createBitmap.getWidth(),ScreenUtil.instance.getNavigationBarHeight());
//                                    BitmapUtil.saveBitmapToFile(createBitmap,path + FileUtil.instance.getFileName(), Bitmap.CompressFormat.JPEG);



                                    if (!bitmapList.isEmpty()) {
                                        if (StitchUtil.bitmapEqual(createBitmap,bitmapList.get(bitmapList.size() - 1))) {
                                            LogUtil.d(TAG,"当前图片和上一张相同");
                                            Toast.makeText(ScreenShotService.this,"已经滑到底部，即将合并",Toast.LENGTH_LONG).show();
                                            // 认为已经滑动底部了，准备合并
                                            doMerge();
                                            return;
                                        }
                                    }

                                    bitmapList.add(createBitmap);

                                    if(shot_screen){//单张图
                                        LogUtil.d(TAG,"capture list size===== " + bitmapList.size());
                                        doMerge();
                                        shot_screen=false;
                                        return;
                                    }



                                    if (isClickCompleteButton) {
                                        Log.e(TAG, "onImageAvailable: ====>>06" );
                                        doMerge();

                                    } else {
                                        if (bitmapList.size() == 50) {
                                            Log.e(TAG, "onImageAvailable: ====>>07" );
                                            Toast.makeText(ScreenShotService.this,"达到最大截图数量，即将合并",Toast.LENGTH_LONG).show();
                                            doMerge();
                                        } else {
                                            Log.e(TAG, "onImageAvailable: ====>>08" );
//                                            mFloatButtonWindow.show();
                                            capture = false;
                                            LocalMessageManager.getInstance().sendEmptyMessage(MessageWhatConstant.MESSAGE_WHAT_DO_SCROLL_START);
                                        }
                                    }
                                }
                            } catch (Throwable throwable) {
                                Log.e(TAG, "onImageAvailable: ====>>09" );
                                throwable.printStackTrace();
                                Toast.makeText(ScreenShotService.this,"截图已达最大数，即将合并",Toast.LENGTH_LONG).show();
                                doMerge();
                            }
                        }

                        if (image != null) {
                            image.close();
                        }
                    }
                }
            },mHandler);
        }
    }

    /**
     * 虚拟显示
     */
    private void virtualDisplay() {
        LogUtil.d(TAG,"virtualDisplay..mediaProjection = " + mediaProjection);
        if (mediaProjection != null) {
            int dpi = getResources().getDisplayMetrics().densityDpi;
            int flag =
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
                            | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
            LogUtil.d(TAG,"virtualDisplay flag = " + flag);
            mVirtualDisplay = mediaProjection.createVirtualDisplay("long_shot_screen",screenWidth,screenHeight,dpi,16,imageReader.getSurface(),null,null);
        }
    }

    /**
     * 合并bitmap，生成长图
     */
    private void mergeBitmap(){
        LogUtil.d(TAG,"mergeBitmap====");
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                LogUtil.d(TAG,"ScreenShotManager mergeBitmap size = ====" + bitmapList.size());
                String path = FileUtil.instance.getSavePath(ScreenShotService.this);
                FileUtil.instance.mkdirs(path);

                if (!bitmapList.isEmpty()) {
                    Bitmap bitmap = bitmapList.get(0);
                    final boolean[] isMergeError = {false};
                    for (int i = 1;i < bitmapList.size();i++) {
                        Bitmap next = bitmapList.get(i);
                        if (next != null) {
                            if (!isMergeError[0]) {
                                LogUtil.d(TAG,"I = " + i);
                                bitmap = StitchUtil.merge(bitmap,next,new StitchUtil.MergeListener() {
                                    @Override
                                    public void onError(Throwable throwable,Bitmap bitmap) {
                                        LogUtil.d(TAG,"merge onError bitmap ===== " + bitmap);
                                        isMergeError[0] = true;
                                    }
                                });
                                // 合并一张，回收一张
                                next.recycle();
                                if (mScreenShotStateCallback != null) {
                                    mScreenShotStateCallback.onStitchProgress(i,bitmapList.size() - 1);
                                }
                            } else {
                                LogUtil.d(TAG,"mergeBitmap error==== ,break");
                                Toast.makeText(ScreenShotService.this,"合并已达最大数，即将显示当前合并效果",Toast.LENGTH_LONG).show();
                                break;
                            }
                        }
                    }
                    LogUtil.d(TAG,"mergeBitmap bitmap ===== " + bitmap);

                    if (bitmap != null) {
                        BitmapUtil.saveBitmapToFile(bitmap, path + FileUtil.instance.getFileName(), Bitmap.CompressFormat.JPEG);
                        LogUtil.d(TAG,"mergeBitmap mScreenShotCallback ===== " + mScreenShotStateCallback);
                        if (mScreenShotStateCallback != null) {
                            mScreenShotStateCallback.onShotCompleted(bitmap);
                        }
                    }

                    recycleBitmap();
                }
            }
        });
    }

    /**
     * 回收位图
     */
    private void recycleBitmap() {
        LogUtil.d(TAG,"recycle bitmap size = " + bitmapList.size());
        bitmapList.clear();
    }

    /**
     * 释放资源
     */
    private void release(){
        LogUtil.d(TAG,"release .... ");
        try {
            if (mVirtualDisplay != null) {
                mVirtualDisplay.release();
                mVirtualDisplay = null;
            }

            if (imageReader != null) {
                imageReader.close();
                imageReader = null;
            }

            if (mediaProjection != null) {
                mediaProjection.stop();
                mediaProjection = null;
            }

            LogUtil.d(TAG,"release .... mVirtualDisplay = " + mVirtualDisplay+ ",imageReader = " + imageReader + ";mediaProjection = " + mediaProjection);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 启动通知到状态栏，录屏权限需要前台通知权限
     */
    private void notification() {
        LogUtil.d(TAG,"notification: " + Build.VERSION.SDK_INT);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            Intent notificationIntent = new Intent(this, ScreenShotService.class);
            // android 12需要加FLAG_IMMUTABLE
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
            NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), getIconResourcesId()))
                    .setSmallIcon(getIconResourcesId())
                    .setContentTitle("Starting Service")
                    .setContentText("Starting monitoring service")
                    .setContentIntent(pendingIntent);
            Notification notification = notificationBuilder.build();
            NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
            channel.setDescription(CHANNEL_DESCRIPTION);
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(channel);
            startForeground(NOTIFICATION_ID, notification);
        }
    }

    private int getIconResourcesId() {
        return getIconResourcesId("");
    }

    private int getIconResourcesId(String name) {
        int id = getResources().getIdentifier(name, "mipmap", getPackageName());
        if (id > 0) {
            return id;
        }

        id = getResources().getIdentifier("ic_launcher", "mipmap", getPackageName());
        return id;
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(EventCancelGesture event) {
        // 显示按钮
        mFloatButtonWindow.show();
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy: ====>>" );
        LocalMessageManager.getInstance().removeListener(this);
        release();
        EventBus.getDefault().unregister(this);
    }

}
